//===--- FloatingPoint.swift.gyb ------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftShims

%{
#
# Utility code for later in this template
#

# // Bit counts for all floating point types. 
# // 80-bit floating point types are only permitted on x86 architectures. This
# // restriction is handled via #if's in the generated code.
allFloatBits = [32, 64, 80]

# Bit counts for all int types
allIntBits = [8, 16, 32, 64, 'Int']

# Number of bits in the Builtin.Word type
word_bits = int(CMAKE_SIZEOF_VOID_P) * 8

# Number of bits in integer literals.
builtinIntLiteralBits = 2048

def allInts():
    for bits in allIntBits:
        for signed in False, True:
            yield bits,signed

def baseIntName(name):
    return 'Int' if name == 'Int' else 'Int' + str(name)

def builtinIntName(name):
    return 'Int' + str(word_bits) if name == 'Int' else 'Int' + str(name)

def intName(name, signed):
    return ('' if signed else 'U') + baseIntName(name)

def floatName(bits):
    if bits == 32:
        return 'Float'
    if bits == 64:
        return 'Double'
    if bits == 80:
        return 'Float80'

def cFuncSuffix(bits):
    if bits == 32:
        return 'f'
    if bits == 64:
        return ''
    if bits == 80:
        return 'l'

def llvmIntrinsicSuffix(bits):
    if bits == 32:
        return 'f32'
    if bits == 64:
        return 'f64'
    if bits == 80:
        return 'f80'

def getInfBitPattern(bits):
    if bits == 32:
        return '0x7f800000'
    if bits == 64:
        return '0x7ff0000000000000'
    return 'error'

def getQuietNaNBitPattern(bits):
    if bits == 32:
        return '0x7fc00000'
    if bits == 64:
        return '0x7ff8000000000000'
    return 'error'

def getSignalingNanBitPattern(bits):
    if bits == 32:
        return '0x7fa00000'
    if bits == 64:
        return '0x7ff4000000000000'
    return 'error'

def getMinNormalBitPattern(bits):
    if bits == 32:
        return '0x00800000'
    if bits == 64:
        return '0x0010000000000000'
    return 'error'

def getExponentBitCount(bits):
    if bits == 32:
        return '8'
    if bits == 64:
        return '11'
    return 'error'

def getSignificantBitCount(bits):
    if bits == 32:
        return '23'
    if bits == 64:
        return '52'
    return 'error'

def getInfinityExponent(bits):
    if bits == 32:
        return '0xff'
    if bits == 64:
        return '0x7ff'
    return 'error'

def mantissaOffset(floatBits):
    if floatBits == 32:
        return 23
    if floatBits == 64:
        return 52
    if floatBits == 80:
        return 63

def intFormatFix(bits):
    if bits == 'Int':
        return int(CMAKE_SIZEOF_VOID_P) * 8
    return bits

def positivePrefix(floatBits):
    return 0b1 << (floatBits - 2)

def positiveExponent(floatBits, intBits):
    return ((intBits - 3) << mantissaOffset(floatBits))

def mantissaBits(floatBits, intBits):
    offset = mantissaOffset(floatBits)
    if intBits > offset:
        return ((1 << intBits) - 4) >> (intBits - offset)
    else:
        return ((1 << intBits) - 4) << (offset - intBits)

def getMaxFloat(floatBits, intBits):
    maxFloat = (positivePrefix(floatBits) +
        positiveExponent(floatBits, intBits) + mantissaBits(floatBits, intBits))
    return "0x%0.x" % maxFloat

def negativePrefix(floatBits):
    return 0b11 << (floatBits - 2)

def negativeExponent(floatBits, intBits):
    return ((intBits - 2) << mantissaOffset(floatBits))

def getMinFloat(floatBits, intBits):
    minFloat = negativePrefix(floatBits) + negativeExponent(floatBits, intBits)
    return "0x%0.x" % minFloat

def incIfSigned(bits, signed):
    if not(signed):
        return bits + 1
    else:
        return bits

}%

% for bits in allFloatBits:
%   Self = floatName(bits)

% if bits == 80:
#if arch(i386) || arch(x86_64)
% end

public struct ${Self} {
  public // @testable
  var _value: Builtin.FPIEEE${bits}

  /// Create an instance initialized to zero.
  @_transparent public
  init() {
    let zero: Int64 = 0
    self._value = Builtin.uitofp_Int64_FPIEEE${bits}(zero._value)
  }

  @_transparent 
  public // @testable
  init(_bits v: Builtin.FPIEEE${bits}) {
    self._value = v
  }

  /// Create an instance initialized to `value`.
  @_transparent public
  init(_ value: ${Self}) { self = value }
}

extension ${Self} : CustomStringConvertible {
  /// A textual representation of `self`.
  public var description: String {
    return _float${bits}ToString(self)
  }
}

% if bits in allIntBits:
// Not transparent because the compiler crashes in that case.
//@_transparent
extension ${Self} : FloatingPointType {
  public typealias _BitsType = UInt${bits}

  public static func _fromBitPattern(bits: _BitsType) -> ${Self} {
    return ${Self}(_bits: Builtin.bitcast_Int${bits}_FPIEEE${bits}(bits._value))
  }

  public func _toBitPattern() -> _BitsType {
    return _BitsType(Builtin.bitcast_FPIEEE${bits}_Int${bits}(_value))
  }

  @warn_unused_result
  func __getSignBit() -> Int {
    return Int(_toBitPattern() >> ${bits - 1}) & 1
  }

  @warn_unused_result
  func __getBiasedExponent() -> _BitsType {
    return (_toBitPattern() >> ${getSignificantBitCount(bits)}) & ${getInfinityExponent(bits)}
  }

  @warn_unused_result
  func __getSignificand() -> _BitsType {
    let mask: _BitsType = (1 << ${getSignificantBitCount(bits)}) - 1
    return _toBitPattern() & mask
  }

  /// The positive infinity.
  public static var infinity: ${Self} {
    return _fromBitPattern(${getInfBitPattern(bits)})
  }

  /// A quiet NaN.
  public static var NaN: ${Self} {
    return quietNaN
  }

  /// A quiet NaN.
  public static var quietNaN: ${Self} {
    return _fromBitPattern(${getQuietNaNBitPattern(bits)})
  }

  /// `true` iff `self` is negative.
  public var isSignMinus: Bool {
    return __getSignBit() == 1
  }

  /// `true` iff `self` is normal (not zero, subnormal, infinity, or
  /// NaN).
  public var isNormal:  Bool {
    let biasedExponent = __getBiasedExponent()
    return biasedExponent != ${getInfinityExponent(bits)} &&
           biasedExponent != 0
  }

  /// `true` iff `self` is zero, subnormal, or normal (not infinity
  /// or NaN).
  public var isFinite:  Bool {
    return __getBiasedExponent() != ${getInfinityExponent(bits)}
  }

  /// `true` iff `self` is +0.0 or -0.0.
  public var isZero:  Bool {
    // Mask out the sign bit.
    let mask: _BitsType = (1 << (${bits} - 1)) - 1
    return (_toBitPattern() & mask) == 0
  }

  /// `true` iff `self` is subnormal.
  public var isSubnormal:  Bool {
    if __getBiasedExponent() == 0 {
      return __getSignificand() != 0
    }
    return false

    // Alternative implementation:
    // return !isNan() &&
    //     abs(self) < ${Self}._fromBitPattern(${getMinNormalBitPattern(bits)})
    //
    // But because we need to check for !isNan(), and do it safely in case of
    // SNaN, we need to go down to the bit level, so open-coding the combined
    // condition is going to be faster.
  }

  /// `true` iff `self` is infinity.
  public var isInfinite:  Bool {
    if __getBiasedExponent() == ${getInfinityExponent(bits)} {
      return __getSignificand() == 0
    }
    return false

    // Alternative implementation that is not safe in case of SNaN:
    // return abs(self) == ${Self}.infinity()
  }

  /// `true` iff `self` is NaN.
  public var isNaN:  Bool {
    if __getBiasedExponent() == ${getInfinityExponent(bits)} {
      return __getSignificand() != 0
    }
    return false

    // Alternative implementation that is not safe in case of SNaN:
    // return self != self
  }

  /// `true` iff `self` is a signaling NaN.
  public var isSignaling: Bool {
    if __getBiasedExponent() == ${getInfinityExponent(bits)} {
      // IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded
      // with the first bit of the trailing significand being 0.  If the first
      // bit of the trailing significand field is 0, some other bit of the
      // trailing significand field must be non-zero to distinguish the NaN
      // from infinity.
      let significand = __getSignificand()
      if significand != 0 {
        return (significand >> (${getSignificantBitCount(bits)} - 1)) == 0
      }
    }
    return false
  }
}

// Not @_transparent because the function is too complex.
extension ${Self} /* : FloatingPointType */ {
  /// The IEEE 754 "class" of this type.
  public var floatingPointClass: FloatingPointClassification {
    get {
      let biasedExponent = __getBiasedExponent()
      if biasedExponent == ${getInfinityExponent(bits)} {
        let significand = __getSignificand()
        // This is either +/-inf or NaN.
        if significand == 0 {
          return isSignMinus ? .NegativeInfinity : .PositiveInfinity
        }
        let isQNaN = (significand >> (${getSignificantBitCount(bits)} - 1)) == 1
        return isQNaN ? .QuietNaN : .SignalingNaN
      }

      // OK, the number is finite.
      let isMinus = isSignMinus
      if biasedExponent != 0 {
        return isMinus ? .NegativeNormal : .PositiveNormal
      }

      // Exponent is zero.
      if __getSignificand() == 0 {
        return isMinus ? .NegativeZero : .PositiveZero
      }
      return isMinus ? .NegativeSubnormal : .PositiveSubnormal
    }
  }
}
% end

@_transparent
extension ${Self} : _BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible {
  public
  init(_builtinIntegerLiteral value: Builtin.Int${builtinIntLiteralBits}){
    self = ${Self}(_bits: Builtin.itofp_with_overflow_Int${builtinIntLiteralBits}_FPIEEE${bits}(value))
  }

  /// Create an instance initialized to `value`.
  public init(integerLiteral value: Int64) {
    self = ${Self}(_bits: Builtin.sitofp_Int64_FPIEEE${bits}(value._value))
  }
}

#if arch(i386) || arch(x86_64)

% builtinFloatLiteralBits = 80
@_transparent
extension ${Self} : _BuiltinFloatLiteralConvertible {
  public
  init(_builtinFloatLiteral value: Builtin.FPIEEE${builtinFloatLiteralBits}) {
%   if bits == builtinFloatLiteralBits:
    self = ${Self}(_bits: value)
%   elif bits < builtinFloatLiteralBits:
    self = ${Self}(_bits: Builtin.fptrunc_FPIEEE${builtinFloatLiteralBits}_FPIEEE${bits}(value))
%   else:
    // FIXME: This is actually losing precision <rdar://problem/14073102>.
    self = ${Self}(Builtin.fpext_FPIEEE${builtinFloatLiteralBits}_FPIEEE${bits}(value))
%   end
  }
}

#else

% builtinFloatLiteralBits = 64
@_transparent
extension ${Self} : _BuiltinFloatLiteralConvertible {
  public
  init(_builtinFloatLiteral value: Builtin.FPIEEE${builtinFloatLiteralBits}) {
%   if bits == builtinFloatLiteralBits:
    self = ${Self}(_bits: value)
%   elif bits < builtinFloatLiteralBits:
    self = ${Self}(_bits: Builtin.fptrunc_FPIEEE${builtinFloatLiteralBits}_FPIEEE${bits}(value))
%   else:
    // FIXME: This is actually losing precision <rdar://problem/14073102>.
    self = ${Self}(Builtin.fpext_FPIEEE${builtinFloatLiteralBits}_FPIEEE${bits}(value))
%   end
  }
}

#endif

@_transparent
extension ${Self} : FloatLiteralConvertible {
  /// Create an instance initialized to `value`.
  public init(floatLiteral value: ${Self}) {
    self = value
  }
}

@_transparent
@warn_unused_result
public func ==(lhs: ${Self}, rhs: ${Self}) -> Bool {
  return Bool(Builtin.fcmp_oeq_FPIEEE${bits}(lhs._value, rhs._value))
}

@_transparent
@warn_unused_result
public func != (lhs: ${Self}, rhs: ${Self}) -> Bool {
  return Bool(Builtin.fcmp_une_FPIEEE${bits}(lhs._value, rhs._value))
}

@_transparent
@warn_unused_result
public func <(lhs: ${Self}, rhs: ${Self}) -> Bool {
  return Bool(Builtin.fcmp_olt_FPIEEE${bits}(lhs._value, rhs._value))
}

@_transparent
@warn_unused_result
public func > (lhs: ${Self}, rhs: ${Self}) -> Bool {
  return Bool(Builtin.fcmp_ogt_FPIEEE${bits}(lhs._value, rhs._value))
}

@_transparent
@warn_unused_result
public func <= (lhs: ${Self}, rhs: ${Self}) -> Bool {
  return Bool(Builtin.fcmp_ole_FPIEEE${bits}(lhs._value, rhs._value))
}

@_transparent
@warn_unused_result
public func >= (lhs: ${Self}, rhs: ${Self}) -> Bool {
  return Bool(Builtin.fcmp_oge_FPIEEE${bits}(lhs._value, rhs._value))
}

@_transparent
extension ${Self} : Comparable, Equatable {
}

extension ${Self} : Hashable {
  /// The hash value.
  ///
  /// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`.
  ///
  /// - Note: The hash value is not guaranteed to be stable across
  ///   different invocations of the same program.  Do not persist the
  ///   hash value across program runs.
  public var hashValue: Int {
  // FIXME: Float80 does not have _toBitPattern.
  % if bits != 80:
  // -0.0.hashValue must == 0.0.hashValue. So we need to check for -0.0.
  % if bits == 32:
    if self._toBitPattern() == 0x8000_0000 {
  % elif bits == 64:
    if self._toBitPattern() == 0x8000_0000_0000_0000 {
  % else:
    error unhandled float size ${bits}
  % end
      return 0.0.hashValue
    } else {
  % end
      let asBuiltinInt = Builtin.bitcast_FPIEEE${bits}_Int${bits}(_value)
  %   if bits >= 64:
      return Int(Builtin.truncOrBitCast_Int${bits}_Word(asBuiltinInt))
  %   elif bits <= 32:
      return Int(Builtin.sextOrBitCast_Int${bits}_Word(asBuiltinInt))
  %   else:
      error unhandled float size ${bits}
  %   end
  % if bits != 80:
    }
  % end
  }
}

@_transparent
extension ${Self} : AbsoluteValuable {
  /// Returns the absolute value of `x`.
  @_transparent
  @warn_unused_result
  public static func abs(x: ${Self}) -> ${Self} {
    return ${Self}(_bits: Builtin.int_fabs_FPIEEE${bits}(x._value))
  }
}

@_transparent
@warn_unused_result
public prefix func +(x: ${Self}) -> ${Self} {
  return x
}

@_transparent
@warn_unused_result
public prefix func -(x: ${Self}) -> ${Self} {
  return ${Self}(_bits: Builtin.fneg_FPIEEE${bits}(x._value))
}

//===----------------------------------------------------------------------===//
// Explicit conversions between types.
//===----------------------------------------------------------------------===//

// Construction from integers.
@_transparent
extension ${Self} {
% for (srcBits, srcSigned) in allInts():
%    That = intName(srcBits, srcSigned)
%    ThatBuiltinName = builtinIntName(srcBits)
%    sign = 's' if srcSigned else 'u'
  public init(_ v: ${That}) {
    _value = Builtin.${sign}itofp_${ThatBuiltinName}_FPIEEE${bits}(v._value)
  }
% end
}

// Construction from other floating point numbers.
@_transparent
extension ${Self} {
% for srcBits in allFloatBits:
%   That = floatName(srcBits)
%   if Self != That:

%     if srcBits == 80:
#if arch(i386) || arch(x86_64)
%     end

  /// Construct an instance that approximates `other`.
  public init(_ other: ${That}) {
%     if srcBits > bits:
    _value = Builtin.fptrunc_FPIEEE${srcBits}_FPIEEE${bits}(other._value)
%     else:
    _value = Builtin.fpext_FPIEEE${srcBits}_FPIEEE${bits}(other._value)
%     end
  }

%     if srcBits == 80:
#endif
%     end

%   end
% end
}

//===----------------------------------------------------------------------===//
// Standard Operator Table
//===----------------------------------------------------------------------===//

@_transparent
public prefix func ++ (inout rhs: ${Self}) -> ${Self} { rhs += 1.0; return rhs }
@_transparent
public prefix func -- (inout rhs: ${Self}) -> ${Self} { rhs -= 1.0; return rhs }
@_transparent
public postfix func ++ (inout lhs: ${Self}) -> ${Self} { let tmp = lhs; lhs += 1.0; return tmp }
@_transparent
public postfix func -- (inout lhs: ${Self}) -> ${Self} { let tmp = lhs; lhs -= 1.0; return tmp }



@_transparent
extension ${Self} : Strideable {
  /// Returns a stride `x` such that `self.advancedBy(x)` approximates
  /// `other`.
  ///
  /// - Complexity: O(1).
  @_transparent public
  func distanceTo(other: ${Self}) -> ${Self} {
    return other - self
  }
  
  /// Returns a `Self` `x` such that `self.distanceTo(x)` approximates
  /// `n`.
  ///
  /// - Complexity: O(1).
  @_transparent public
  func advancedBy(amount: ${Self}) -> ${Self} {
    return self + amount
  }
}

% for op, name in ('+','fadd'), ('-','fsub'),('*','fmul'), ('/','fdiv'):
@_transparent
@warn_unused_result
public func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
  return ${Self}(_bits: Builtin.${name}_FPIEEE${bits}(lhs._value, rhs._value))
}
% end

// Binary Remainder.
// The sign of the result matches the sign of the dividend.
// 1) This is consistent with '%' in C#, D, Java, and JavaScript
// 2) C99 requires this behavior for fmod*()
// 3) C++11 requires this behavior for std::fmod*()
@warn_unused_result
@_silgen_name("_swift_fmod${cFuncSuffix(bits)}")
public func % (lhs: ${Self}, rhs: ${Self}) -> ${Self}

// See Bool.swift for && and ||
// In C, 120 is &&
// In C, 110 is ||

// In C, 100 is ?:
// In C, 90 is =, *=, += etc.

% for op in '+', '-', '*', '/', '%':
@_transparent
public func ${op}= (inout lhs: ${Self}, rhs: ${Self}) { lhs = lhs ${op} rhs }
% end

% if bits == 80:
#endif
% end

% end # for bits in allFloatBits

// Construction of integers from floating point numbers.
% for (bits, signed) in allInts():
%   sign = 's' if signed else 'u'
%   Self = intName(bits, signed)
%   BuiltinName = builtinIntName(bits)
@_transparent
extension ${Self} {
%   for srcBits in allFloatBits:
%     That = floatName(srcBits)

%     if srcBits == 80:
#if arch(i386) || arch(x86_64)
%     end

  /// Construct an instance that approximates `other`.
  public init(_ other: ${That}) {
%     if srcBits != 80:
    // FIXME: Float80 does not have 'isFinite' property.
    // <rdar://problem/17958458> Int(Float80.quietNaN) is garbage
    // <rdar://problem/17959546> Float80.isFinite is missing
    _precondition(
      other.isFinite,
      "floating point value can not be converted to ${Self} because it is either infinite or NaN")
%      if signed:
    // FIXME: Float80 doesn't have a _fromBitPattern
    // ${That}(roundTowardsZero: ${Self}.min)
    // > ${getMinFloat(srcBits, incIfSigned(intFormatFix(bits), signed))}
    _precondition(other >= ${That}._fromBitPattern(${getMinFloat(srcBits,
      incIfSigned(intFormatFix(bits), signed))}),
      "floating point value can not be converted to ${Self} because it is less than ${Self}.min")
%      else:
    _precondition(other >= (0.0 as ${That}),
      "floating point value can not be converted to ${Self} because it is less than ${Self}.min")
%      end
    // ${That}(roundTowardsZero: ${Self}.max)
    // > ${getMaxFloat(srcBits, incIfSigned(intFormatFix(bits), signed))}
    _precondition(other <= ${That}._fromBitPattern(${getMaxFloat(srcBits,
      incIfSigned(intFormatFix(bits), signed))}),
      "floating point value can not be converted to ${Self} because it is greater than ${Self}.max")

%     end
    self._value =
      Builtin.fpto${sign}i_FPIEEE${srcBits}_${BuiltinName}(other._value)
  }

%      if srcBits == 80:
#endif
%       end

%   end
}

% end

// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End:
